import sys
from math import cos, pi
from OCC.Core.BRepAlgoAPI import BRepAlgoAPI_Fuse
from OCC.Core.BRepFilletAPI import BRepFilletAPI_MakeFillet, BRepFilletAPI_MakeChamfer
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakeCylinder
from OCC.Display.SimpleGui import init_display
from OCC.Core.gp import gp_Pnt
from OCC.Extend.TopologyUtils import TopologyExplorer
from OCC.Core.TopTools import TopTools_IndexedMapOfShape
from OCC.Core.TopTools import TopTools_IndexedDataMapOfShapeListOfShape
import OCC.Core.TopAbs as TopAbs
from OCC.Core.TopExp import topexp_MapShapesAndAncestors,TopExp_Explorer
from OCC.Core.TopoDS import topods_Edge, topods_Face
from OCC.Core.BRepFeat import BRepFeat_MakeCylindricalHole
from OCC.Core.gp import gp_Ax2, gp_Pnt, gp_Dir, gp_Ax1, gp_Trsf, gp_Vec
from OCC.Core.BRepBuilderAPI import (BRepBuilderAPI_MakeWire, BRepBuilderAPI_MakeEdge,
	                                 BRepBuilderAPI_MakeFace, BRepBuilderAPI_GTransform)
from OCC.Core.Geom import Geom_Plane
from OCC.Core.BRepPrimAPI import BRepPrimAPI_MakeBox, BRepPrimAPI_MakePrism
from OCC.Core.BRepFeat import (BRepFeat_MakePrism, BRepFeat_MakeDPrism, BRepFeat_SplitShape,
                               BRepFeat_MakeLinearForm, BRepFeat_MakeRevol)
from OCC.Core.BRep import BRep_Tool
# from part import Part
# from part_new import Part
import numpy as np
#display, start_display, add_menu, add_function_to_menu = init_display('wx')


class Rounding():

    def __init__(self,solid,r,index_list=None):
        self.solid = solid
        self.r = r
        self.fillet_ = BRepFilletAPI_MakeFillet(self.solid)
        self.index_list = index_list
        self.topology = TopologyExplorer(myShape=self.solid)
        self.shape_map = TopTools_IndexedMapOfShape()

    def edges_in(self):
        for e in self.topology.edges():
            self.shape_map.Add(e)

    def faces_in(self):
        for f in self.topology.faces():
            self.shape_map.Add(f)


    def fillet(self):
        if self.index_list is None:
            for e in TopologyExplorer(self.solid).edges():
                self.fillet_.Add(self.r,e)
        else:
            for index in self.index_list:
                e=self.shape_map.FindKey(index)
                self.fillet_.Add(self.r,e)

    def filleted_shape(self):
        self.edges_in()
        self.fillet()
        return self.fillet_.Shape()


class Chamfer():

    def __init__(self, solid, chamfer_detail=None):
        self.solid = solid
        self.chamfer = BRepFilletAPI_MakeChamfer(self.solid)
        self.chamfer_detail = chamfer_detail
        self.shape_map = TopTools_IndexedDataMapOfShapeListOfShape()

        self.topology = TopologyExplorer(myShape=self.solid)

    def fillet(self):
        topexp_MapShapesAndAncestors(self.solid, TopAbs.TopAbs_EDGE, TopAbs.TopAbs_FACE, self.shape_map)
        for chamfer in self.chamfer_detail:
            E = topods_Edge(self.shape_map.FindKey(chamfer['edge_id']))
            if chamfer['face']=="FIRST":
                F = topods_Face(self.shape_map.FindFromIndex(chamfer['edge_id']).First())
            elif chamfer['face']=="LAST":
                F = topods_Face(self.shape_map.FindFromIndex(chamfer['edge_id']).Last())
            self.chamfer.Add(chamfer['dis_1'], chamfer['dis_2'], E, F)

    def filleted_shape(self):
        self.fillet()
        return self.chamfer.Shape()


class CylindricalHole():
    def __init__(self,shape,point,direction,high,radius):
        self.shape=shape
        self.point=point
        self.direction=direction
        self.high=high
        self.radius=radius

    def make_hole(self):
        hole_maker = BRepFeat_MakeCylindricalHole()
        hole_origin = gp_Ax1(self.point, self.direction)
        hole_maker.Init(self.shape, hole_origin)
        hole_maker.Build()
        if self.high:
            try:
                hole_maker.PerformBlind(float(self.radius), self.high)
                if hole_maker.Status() == 2:
                    hole_maker.Perform(float(self.radius))
            except Exception as e:
                print(e)
        else:
            hole_maker.Perform(float(self.radius))
        self.shape = hole_maker.Shape()
        return self.shape

# shape=BRepPrimAPI_MakeBox(100,100,100).Shape()
# point=gp_Pnt(50,50,0)
# direction=gp_Dir(0,0,1)
# high=50
# radius=10
# move_directions=[[0,10,0],[0,-10,0]]
# C=CylindricalHole(shape,point,direction,high=None,radius=radius)
# display.DisplayShape(C.make_hole())
# display.FitAll()
# start_display()

class LinearForm():
    def __init__(self, shape, plane, wire,move_directions, operations_num):
        self.shape = shape
        self.plane = plane
        self.wire = wire
        self.move_directions = move_directions
        self.operations_num = operations_num


    def get_plane(self):
        p = self.plane["original_point"]
        gp = gp_Pnt(p[0],p[1],p[2])
        v = self.plane["normal"]
        gv = gp_Dir(v[0],v[1],v[2])
        return Geom_Plane(gp,gv)

    def parse_move_directions(self):
        dirs = self.move_directions
        direction1 = gp_Vec(dirs[0][0], dirs[0][1], dirs[0][2])
        direction2 = gp_Vec(dirs[1][0], dirs[1][1], dirs[1][2])
        return direction1,direction2

    def make_features(self):
        self.parse_move_directions()
        aform = BRepFeat_MakeLinearForm(self.shape, self.wire, self.get_plane(),
                                        self.parse_move_directions()[0], self.parse_move_directions()[1],
                                        self.operations_num, True)
        aform.Perform()
        return aform.Shape()


shape=BRepPrimAPI_MakeBox(100,100,100).Shape()
wire=BRepBuilderAPI_MakeWire(BRepBuilderAPI_MakeEdge(gp_Pnt(50., 45., 100.),
                                                         gp_Pnt(50., 45., 0.)).Edge()).Wire()

# plane={"original_point":[0,45,0],
#        "normal":[0,1,0]}
#
# move_directions=[[0,10,0],[0,-10,0]]
# L=LinearForm(shape,plane,wire,move_directions,0)
# display.DisplayShape(L.make_features())
# display.FitAll()
# start_display()

